mod _dice_data;

use std::{
    fs,
    thread,
    error::Error,
    path::PathBuf,
    sync::{
        Arc,
    }
};
use std::fmt::{Display, Formatter};
use std::sync::Mutex;
use std::thread::JoinHandle;
use csv::Reader;
use serde::Deserialize;
use chrono::Local;
use crate::_dice_data::{DiceData, RowData};

const PATH: &str = "./datasets/";


fn main() {
    let time1 = Local::now().timestamp_millis();
    let data = Arc::new(Mutex::new(DiceData::new()));
    let entries: Vec<PathBuf>
        = fs::read_dir(PATH)
            .unwrap()
            .filter_map(|entry| entry.ok().map(|e| e.path()))
            .collect();

    for handle in worker(entries, Arc::clone(&data)) {
        handle.join().expect("发生什么事了")
    }
    let time2 = Local::now().timestamp_millis();
    println!("{}", data.lock().unwrap());
    data.lock().unwrap().write_to_json("./output_test.json");
    println!("Used {} ms.", time2 - time1);
}

fn worker(entries: Vec<PathBuf>, final_data: Arc<Mutex<DiceData>>) -> Vec<JoinHandle<()>> {
    let sub_entries: Vec<Vec<_>>
        = entries
            .chunks(entries.len() / 8)
            .map(|chunk| chunk.to_vec())
            .collect();

    let mut handles = vec![];
    for sub_entry in sub_entries { // 多线程
        let final_data = Arc::clone(&final_data);
        let handle = thread::spawn(move || {
            let mut total_data = DiceData::new();

            for entry in sub_entry {
                let mut star_flags = [false, false, false, false, false];
                let mut user_data = DiceData::new();

                for row in read_file(&entry).unwrap() {
                    let index = match row.gacha_type {
                        100 => 0, 200 => 1, 301 => 2, 400 => 3, 302 => 4,
                        _ => unreachable!()
                    };
                    if !star_flags[index] {
                        if row.rank_type == 5 { star_flags[index] = true }
                        continue
                    }
                    user_data.record(&row)
                }
                total_data.append(&user_data)
            }
            let mut final_data = final_data.lock().unwrap();
            final_data.append(&total_data);
            println!("Thread {:?} finished", thread::current().id())
        });
        handles.push(handle)
    }
    handles
}

fn read_file(dir_entry: &PathBuf) -> Result<Vec<RowData>, Box<dyn Error>> {
    let handle = fs::read(dir_entry.as_path())?;
    let mut ret = vec![];
    let mut reader = Reader::from_reader(handle.as_slice());
    for result in reader.deserialize() {
        let row: RowData = result?;
        ret.push(row);
    }
    Ok(ret)
}

